#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UTable.ObjectManager;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using UTable.Objects;
using UTable.Logger;

namespace UTable.Input
{
    public class InputManagerImpl : IInputManager
    {
        private IVisualTree _visualTree;

        private Collection<IInputProvider> _inputProviders;

        private Collection<IHook> _hooks = new Collection<IHook>();

        private Dictionary<Type, Collection<IInputMapper>> _inputMappers;

        public InputManagerImpl()
        {
            _inputProviders = new Collection<IInputProvider>();
            _inputMappers = new Dictionary<Type, Collection<IInputMapper>>();
        }

        void OnInputProviderAdded(IInputProvider provider)
        {
            provider.InputTriggered += OnInputReceived;
        }
        void OnInputProviderRemoved(IInputProvider provider)
        {
            provider.InputTriggered -= OnInputReceived;
        }

        void OnInputReceived(InputEventArgs args)
        {
            // Send the input event to the hooks
            foreach (IHook hook in _hooks)
            {
                if (hook.Dispatcher != null)
                {
                    hook.Dispatcher.BeginInvoke(new InputEventHandler(hook.OnInputReceived), new object[] { args });
                }
            }
            if (InputMappers.ContainsKey(args.GetType()))
            {
                Collection<IInputMapper> mappers = InputMappers[args.GetType()];
                if (InputDetected != null)
                {
                    foreach (IInputMapper mapper in mappers)
                    {
                        Collection<ManagedInputEventArgs> inputs = mapper.MapInput(args);
                        foreach (ManagedInputEventArgs input in inputs)
                        {
                            if (InputDetected != null)
                                InputDetected(input);
                        }
                    }
                }
            }
        }

        void OnMappedInputRecieved(ManagedInputEventArgs args)
        {
            if (args != null && InputDetected != null)
                InputDetected(args);
        }

        #region IInputManager Members

        public Dictionary<Type, Collection<IInputMapper>> InputMappers 
        { 
            get
            {
                return _inputMappers;
            }
        }

        public void RegisterInputProvider(Type inputEventType, IInputProvider provider)
        {
            SLogger.Info("Register Input Provider: " + provider);
            if (!_inputProviders.Contains(provider))
            {
                provider.InputTriggered += OnInputReceived;
                _inputProviders.Add(provider);
            }
        }

        public void UnregisterInputProvider(Type inputEventType, IInputProvider provider)
        {
            if (_inputProviders.Contains(provider))
            {
                provider.InputTriggered -= OnInputReceived;
                _inputProviders.Remove(provider);
            }
        }


        public void RegisterInputMapper(Type inputEventArgsType, IInputMapper mapper)
        {
            SLogger.Info("Register Input Mapper: " + mapper);
            if (InputMappers.ContainsKey(inputEventArgsType))
            {
                InputMappers[inputEventArgsType].Add(mapper);
            }
            else
            {
                Collection<IInputMapper> mappers = new Collection<IInputMapper>();
                mappers.Add(mapper);
                InputMappers.Add(inputEventArgsType, mappers);
            }
            mapper.VisualTree = VisualTree;
            mapper.InputMapped += OnMappedInputRecieved;
        }

        public void UnregisterInputMapper(Type inputEventArgsType, IInputMapper mapper)
        {
            if (InputMappers.ContainsKey(inputEventArgsType))
            {
                InputMappers[inputEventArgsType].Remove(mapper);
            }
            mapper.InputMapped -= OnMappedInputRecieved;
            mapper.VisualTree = null;
        }

        public Collection<IInputMapper> GetInputMappersByType(Type inputEventType)
        {
            if (!InputMappers.ContainsKey(inputEventType))
                return null;
            else
                return InputMappers[inputEventType];
        }

        public Collection<Type> GetRegisteredInputEventTypes()
        {
            Collection<Type> types = new Collection<Type>();
            foreach (Type t in InputMappers.Keys)
                types.Add(t);
            return types;
        }

        public void AddHook(IHook hook)
        {
            _hooks.Add(hook);
        }

        public void RemoveHook(IHook hook)
        {
            _hooks.Remove(hook);
        }

        public IVisualTree VisualTree
        {
            get { return _visualTree; }
            set { _visualTree = value; }
        }

        public void StartWork()
        {
            // TODO
        }

        public event ManagedInputEventHandler InputDetected;

        #endregion
    }
}
